package com.adcc.loadsheet.billing.security;

import com.adcc.aoc.devLib.common.codec.MD5;
import com.adcc.loadsheet.billing.configuration.SystemConfig;
import com.google.common.base.Strings;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultClaims;
import io.jsonwebtoken.security.Keys;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.crypto.SecretKey;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Map;

/**
 * JWT工厂类
 */
@Component
public final class JWTFactory {

    // Token头名称
    public static final String TOKEN_HEADER = "Authorization";

    @Autowired
    private SystemConfig systemConfig;

    // 公共密钥
    private SecretKey secretKey;

    // 公钥
    private PublicKey publicKey;

    // 私钥
    private PrivateKey privateKey;

    @PostConstruct
    private void initialize(){
        try{
            if("RSA".equals(systemConfig.getSecretAlg())){
                KeyPair kp = Keys.keyPairFor(SignatureAlgorithm.RS256);
                publicKey = kp.getPublic();
                privateKey = kp.getPrivate();
            }else{
                String md5 = MD5.getMD5(systemConfig.getSecretKey());
                secretKey = Keys.hmacShaKeyFor(md5.getBytes());
            }
        }catch (Exception ex){

        }
    }

    /**
     * 令牌编码
     * @param token
     * @return
     * @throws Exception
     */
    public String encode(BillingUserToken token) throws Exception{
        try{
            if(token == null){
                throw new NullPointerException("token is null");
            }
            DefaultClaims dc = new DefaultClaims();
            dc.setSubject(token.getBody())
                    .setExpiration(token.getExpiredTime().toDate());
            JwtBuilder jb = Jwts.builder()
                    .setHeader(token.getHeader())
                    .setClaims(dc);
            if("RSA".equals(systemConfig.getSecretAlg())){
                return jb.signWith(privateKey, SignatureAlgorithm.RS256).compact();
            }else{
                return jb.signWith(secretKey, SignatureAlgorithm.HS256).compact();
            }
        }catch (Exception ex){
            throw ex;
        }
    }

    /**
     * 令牌解码
     * @param token
     * @return
     * @throws Exception
     */
    public BillingUserToken decode(String token) throws Exception{
        try{
            if(Strings.isNullOrEmpty(token)){
                throw new NullPointerException("token is null or empty");
            }
            JwtParser jp = Jwts.parser();
            if("RSA".equals(systemConfig.getSecretAlg())){
                jp.setSigningKey(publicKey);
            }else{
                jp.setSigningKey(secretKey);
            }
            Jwt jwt = jp.parse(token);
            if(jwt != null){
                BillingUserToken at = new BillingUserToken();
                if(jwt.getHeader().entrySet().size() > 0){
                    jwt.getHeader().entrySet().forEach(v ->{
                        Map.Entry<String,Object> entry = (Map.Entry<String, Object>) v;
                        at.getHeader().put(entry.getKey(),entry.getValue());
                    });
                }
                if(jwt.getBody() != null){
                    DefaultClaims dc = (DefaultClaims)jwt.getBody();
                    if(!Strings.isNullOrEmpty(dc.getSubject())){
                        at.setBody(dc.getSubject());
                    }
                    if(dc.getExpiration() != null ){
                        at.setExpiredTime(new DateTime(dc.getExpiration()));
                    }
                }
                return at;
            }else{
                throw new NullPointerException("jwt is null parse token error");
            }
        }catch (Exception ex){
            throw ex;
        }
    }
}